package wsp.dailymarket.shopping;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import javax.annotation.Resource;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.model.ArrayDataModel;
import javax.faces.model.DataModel;
import javax.sql.DataSource;
import wsp.dailymarket.auth.AuthenticationBean;
import wsp.dailymarket.deals.DealBean;
import wsp.dailymarket.deals.DealCode;

/**
 * CartBean -- Controller for all customer order related information
 * Including:
 *	  "Shopping Cart"
 *    Past Orders
 *    Wish Lists (Future Feature)
 * @author Matt
 */
@ManagedBean(name = "cartBean")
@SessionScoped
public class CartBean {

	@ManagedProperty(value = "#{authenticationBean}")
	private AuthenticationBean authBean;
	@Resource(name = "jdbc/dmderby")
	private DataSource ds;
	private ArrayList<CartItem> cartData = new ArrayList<CartItem>();
	private int order_id = 0;

	// Called from deal.xhtml
	public String doAddToCart(DealBean theDeal) {
		int searchIndex = this.isDealInCart(theDeal);
		if (searchIndex > -1) {
			cartData.get(searchIndex).incrementQty();
		} else {
			cartData.add(new CartItem(theDeal));
		}
		return "cart";
	}

	// Called from cart.xhtml
	public String doRemoveFromCart(CartItem theItem) {
		int searchIndex = this.isDealInCart(theItem.getDeal());
		if (searchIndex > -1) {
			cartData.remove(searchIndex);
		} else {
			// Error?
		}
		return "cart";
	}

	// Called from cart.xhtml
	public String doUpdateQuantity(CartItem theItem) {
		int searchIndex = this.isDealInCart(theItem.getDeal());
		if (searchIndex > -1) {
			cartData.set(searchIndex, theItem);
		} else {
			// Error?
		}
		return "cart";
	}

	public DataModel<CartItem> getCart() {
		return new ArrayDataModel(cartData.toArray());
	}

	// Called from cart.xhtml
	public String doCheckOut() {
		// Checkout from Cart
		if (!this.isCartEmpty()) {
			if (authBean.getAuthentication() != null && authBean.getAuthentication().isAuthorized()) {
				return "checkout";
			} else {
				authBean.setLoginDestination("checkout");
				return "login";
			}
		} else {
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_ERROR);
			msg.setSummary("You cannot check out with an empty cart!");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return null;
		}
	}

	// Called from checkout.xhtml
	public String doConfirmOrder() {
		// Finish placing order (post to database, etc)
		try {
			Connection conn = null;
			try {
				conn = ds.getConnection();
				Statement stmt = conn.createStatement();
				String sql = "INSERT INTO APP.ORDERS (CLIENT_ID,TS_PLACED,ORDER_STATUS) VALUES ('"
						+ authBean.getAuthentication().getUserID()
						+ "', CURRENT_TIMESTAMP, "
						+ (this.getHasTimedDeals() ? InvoiceBean.STATUS_DEALS_PENDING : InvoiceBean.STATUS_COMPLETED)
						+ ")";
				if (stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS) == 1) {
					ResultSet get_id_rs = stmt.getGeneratedKeys();
					if (get_id_rs.next()) {
						order_id = get_id_rs.getInt(1);
						String line_items_sql;
						for (int i = 0; i < cartData.size(); i++) {
							CartItem item = cartData.get(i);
							line_items_sql = "INSERT INTO APP.DEAL_ORDERS (ORDER_ID, DEAL_ID, STATUS) VALUES ("
									+ order_id
									+ ","
									+ item.getDeal().getID()
									+ ","
									+ (item.getDeal().getTimed() ? InvoiceLineItem.STATUS_PENDING : InvoiceLineItem.STATUS_COMPLETE)
									+ ")";
							if (stmt.executeUpdate(line_items_sql, Statement.RETURN_GENERATED_KEYS) == 1) {
								if (!item.getDeal().getTimed()) {
									// Deal not timed generate codes immediately
									ResultSet get_line_item_id_rs = stmt.getGeneratedKeys();
									if (get_line_item_id_rs.next()) {
										int line_item_id = get_line_item_id_rs.getInt(1);
										String code_sql;
										for (int j = 0; j < item.getQuantity(); j++) {
											code_sql = "INSERT INTO APP.DEAL_CODES (DEAL_ORDER_ID, CODE_DATA, PRICE_POINT) VALUES ("
													+ line_item_id
													+ ",'"
													+ DealCode.generateCode(authBean.getAuthentication().getUserID(), item.getDeal().getCompany(), item.getDeal().getID(), j, System.currentTimeMillis())
													+ "',"
													+ item.getDeal().getPrice()
													+ ")";
											if (stmt.executeUpdate(code_sql) != 1) {
												System.err.println("Code not added: " + code_sql);
											}
										}
									}
								}
							} else {
								FacesMessage msg = new FacesMessage();
								msg.setSeverity(FacesMessage.SEVERITY_FATAL);
								msg.setSummary("Database Error! Could not add line item to database.");
								FacesContext.getCurrentInstance().addMessage(null, msg);
							}
						}
						cartData.clear();
					} else {
						FacesMessage msg = new FacesMessage();
						msg.setSeverity(FacesMessage.SEVERITY_FATAL);
						msg.setSummary("Database Error!");
						FacesContext.getCurrentInstance().addMessage(null, msg);
					}
				}
			} finally {
				if (conn != null) {
					conn.close();
				}
			}
		} catch (SQLException ex) {
			ex.printStackTrace(System.err);
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_FATAL);
			msg.setSummary("Database Error!");
			FacesContext.getCurrentInstance().addMessage(null, msg);
		}
		ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext();
		String view = extContext.getRequestContextPath() + "/customer/invoice.do?order=" + this.order_id;
		String url = extContext.encodeActionURL(view);
		try {
			FacesContext.getCurrentInstance().getExternalContext().redirect(url);
		} catch (IOException ex) {
			FacesContext.getCurrentInstance().getExternalContext().log("Unable to redirect:", ex);
		}
		return null;
	}

	public int isDealInCart(DealBean theDeal) {
		for (int i = 0; i < cartData.size(); i++) {
			if (cartData.get(i).getDeal().getID() == theDeal.getID()) {
				return i;
			}
		}
		return -1;
	}

	public void setAuthBean(AuthenticationBean auth) {
		this.authBean = auth;
	}

	public boolean isCartEmpty() {
		return this.cartData.isEmpty();
	}

	public boolean getHasTimedDeals() {
		for (int i = 0; i < this.cartData.size(); i++) {
			if (this.cartData.get(i).getDeal().getTimed()) {
				return true;
			}
		}
		return false;
	}
}
